/*
 * Copyright (C) 2015-2019 Alibaba Group Holding Limited
 */
#include <k_api.h>
#include "errno.h"
#include "aos/hal/rtc.h"
#include "aos/hal/i2c.h"
#include "aos/kernel.h"
#include "board.h"

#define RTC_DEFAULT_TIME_OUT 0XFFFFFFFF

#define RTC_I2C_BASE_ADDR 0X32

#define RX8010_SEC     0x10
#define RX8010_MIN     0x11
#define RX8010_HOUR    0x12
#define RX8010_WDAY    0x13
#define RX8010_MDAY    0x14
#define RX8010_MONTH   0x15
#define RX8010_YEAR    0x16
#define RX8010_YEAR    0x16
#define RX8010_RESV17  0x17
#define RX8010_ALMIN   0x18
#define RX8010_ALHOUR  0x19
#define RX8010_ALWDAY  0x1A
#define RX8010_TCOUNT0 0x1B
#define RX8010_TCOUNT1 0x1C
#define RX8010_EXT     0x1D
#define RX8010_FLAG    0x1E
#define RX8010_CTRL    0x1F
#define RX8010_RESV30  0x30
#define RX8010_RESV31  0x31
#define RX8010_IRQ     0x32

#define RX8010_EXT_WADA  0x04//BIT(3)
#define RX8010_FLAG_VLF  0x02//BIT(1)
#define RX8010_FLAG_AF   0x04//BIT(3)
#define RX8010_FLAG_TF   0x08//BIT(4)
#define RX8010_FLAG_UF   0x10//BIT(5)
#define RX8010_CTRL_AIE  0x04//BIT(3)
#define RX8010_CTRL_UIE  0x10//BIT(5)
#define RX8010_CTRL_STOP 0x20//BIT(6)
#define RX8010_CTRL_TEST 0x40//BIT(7)
#define RX8010_ALARM_AE  0x40//BIT(7)

static i2c_dev_t rtc_i2c_config;

uint8_t bcd2bin(uint8_t data)
{
    int i=0;
    uint8_t ret_Val = 0;
    uint8_t mask[4] = {0x01,0x02,0x04,0x08};

    for(i=0;i<4;i++)
    {
        if(mask[i]&data)
        {
            ret_Val+=mask[i];
        }
    }

    for(i=0;i<4;i++)
    {
        if(mask[i]&(data>>4))
        {
            ret_Val+=(mask[i]*10);
        }
    }

    return ret_Val;
}

uint8_t  bin2bcd(uint8_t bin)
{
    uint8_t dataH;
    uint8_t dataL;

    dataH = bin / 10;
    dataL = bin - (dataH * 10);

    return (dataH<<4)|dataL;
}

int32_t hal_rtc_init(rtc_dev_t *rtc)
{
    int       ret = 0;
    uint8_t   flag = 0;
    uint8_t   data = 0;
    uint8_t   ctrl[2];
    int       need_clear = 0;

    memset(&rtc_i2c_config, 0, sizeof(rtc_i2c_config));
    rtc_i2c_config.port = 1;
    ret = hal_i2c_init(&rtc_i2c_config);
    if (ret != 0) {
        return -1;
    }

    ret = hal_i2c_mem_read(&rtc_i2c_config, RTC_I2C_BASE_ADDR, RX8010_FLAG, 1, &flag, 1, RTC_DEFAULT_TIME_OUT);
    if (ret != 0) {
        return -1;
    }

    flag &= ~(RX8010_FLAG_VLF);
    ret = hal_i2c_mem_write(&rtc_i2c_config, RTC_I2C_BASE_ADDR, RX8010_FLAG, 1, &flag, 1, RTC_DEFAULT_TIME_OUT);
    if (ret != 0) {
        return -1;
    }

    data = 0xD8;
    ret = hal_i2c_mem_write(&rtc_i2c_config, RTC_I2C_BASE_ADDR, RX8010_RESV17, 1, &data, 1, RTC_DEFAULT_TIME_OUT);
    if (ret != 0) {
        return -1;
    }

    data = 0x00;
    ret = hal_i2c_mem_write(&rtc_i2c_config, RTC_I2C_BASE_ADDR, RX8010_RESV30, 1, &data, 1, RTC_DEFAULT_TIME_OUT);
    if (ret != 0) {
        return -1;
    }


    data = 0x08;
    ret = hal_i2c_mem_write(&rtc_i2c_config, RTC_I2C_BASE_ADDR, RX8010_RESV31, 1, &data, 1, RTC_DEFAULT_TIME_OUT);
    if (ret != 0) {
        return -1;
    }


    data = 0x00;
    ret = hal_i2c_mem_write(&rtc_i2c_config, RTC_I2C_BASE_ADDR, RX8010_IRQ, 1, &data, 1, RTC_DEFAULT_TIME_OUT);
    if (ret != 0) {
        return -1;
    }

    ret = hal_i2c_mem_read(&rtc_i2c_config, RTC_I2C_BASE_ADDR, RX8010_FLAG, 1, &ctrl[0], 2, RTC_DEFAULT_TIME_OUT);
    if (ret != 0) {
        return -1;
    }

    if (ctrl[0] & RX8010_FLAG_VLF) {

        printf("\r\n Frequency stop was detected\r\n");

    }

    if (ctrl[0] & RX8010_FLAG_AF) {
        printf("\r\n Alarm was detected\r\n");
        need_clear = 1;
    }

    if (ctrl[0] & RX8010_FLAG_TF) {
        need_clear = 1;
    }

    if (ctrl[0] & RX8010_FLAG_UF) {
        need_clear = 1;
    }

    if (need_clear) {
        ctrl[0] &= ~(RX8010_FLAG_AF | RX8010_FLAG_TF | RX8010_FLAG_UF);
        ret = hal_i2c_mem_write(&rtc_i2c_config, RTC_I2C_BASE_ADDR, RX8010_FLAG, 1, &ctrl[0], 1, RTC_DEFAULT_TIME_OUT);
    }

    return ret;
}


int32_t hal_rtc_get_time(rtc_dev_t *rtc, rtc_time_t *time)
{
    int ret;
    uint8_t date[7];
    uint8_t flag;

    if ((time == NULL) || (rtc == NULL)) {
        return -1;
    }

    ret = hal_i2c_mem_read(&rtc_i2c_config, RTC_I2C_BASE_ADDR, RX8010_FLAG, 1, &flag, 1, RTC_DEFAULT_TIME_OUT);
    if (ret != 0) {
        return -1;
    }

    if (flag & RX8010_FLAG_VLF)
    {
        printf("\r\n Frequency stop was detected\r\n");
        return 1;
    }

    ret = hal_i2c_mem_read(&rtc_i2c_config, RTC_I2C_BASE_ADDR, RX8010_SEC, 1, &date[0], 7, RTC_DEFAULT_TIME_OUT);
    if (ret != 0) {
        return -1;
    }

    time->year = bcd2bin(date[RX8010_YEAR - RX8010_SEC]);
    time->month= bcd2bin(date[RX8010_MONTH - RX8010_SEC] & 0x1f);
    time->date = bcd2bin(date[RX8010_MDAY - RX8010_SEC] & 0x3f);
    time->hr = bcd2bin(date[RX8010_HOUR - RX8010_SEC] & 0x3f);
    time->min = bcd2bin(date[RX8010_MIN - RX8010_SEC] & 0x7f);
    time->sec = bcd2bin(date[RX8010_SEC - RX8010_SEC] & 0x7f);
    time->weekday = date[RX8010_WDAY - RX8010_SEC] & 0x7f;

    return 0;

}


int32_t hal_rtc_set_time(rtc_dev_t *rtc, const rtc_time_t *time)
{
    int ret = 0;
    uint8_t bcd_date[7];

    if ((time == NULL) || (rtc == NULL)) {
        return -1;
    }

    bcd_date[0] = bin2bcd(time->sec);
    bcd_date[1] = bin2bcd(time->min);
    bcd_date[2] = bin2bcd(time->hr);
    bcd_date[3] = bin2bcd(time->weekday);

    bcd_date[4] = bin2bcd(time->date);
    bcd_date[5] = bin2bcd(time->month);
    bcd_date[6] = bin2bcd(time->year);

    ret = hal_i2c_mem_write(&rtc_i2c_config, RTC_I2C_BASE_ADDR, RX8010_SEC, 1, &bcd_date[0], 3, RTC_DEFAULT_TIME_OUT);
    ret |= hal_i2c_mem_write(&rtc_i2c_config, RTC_I2C_BASE_ADDR, RX8010_WDAY, 1, &bcd_date[3], 1, RTC_DEFAULT_TIME_OUT);
    ret |= hal_i2c_mem_write(&rtc_i2c_config, RTC_I2C_BASE_ADDR, RX8010_MDAY, 1, &bcd_date[4], 3, RTC_DEFAULT_TIME_OUT);

    return ret;
}


int32_t hal_rtc_finalize(rtc_dev_t *rtc)
{
    return hal_i2c_finalize(rtc);
}

